package com.telenav;

import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;

public class Test4 {
	static {
		System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
	}

	/**
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		Mat I = Highgui.imread(new File("data/lena.jpg").getAbsolutePath(), Highgui.CV_LOAD_IMAGE_GRAYSCALE);
		if (I.empty())
			return;

		Mat padded = new Mat(); //expand input image to optimal size
		int m = Core.getOptimalDFTSize(I.rows());
		int n = Core.getOptimalDFTSize(I.cols()); // on the border add zero values
		Imgproc.copyMakeBorder(I, padded, 0, m - I.rows(), 0, n - I.cols(), Imgproc.BORDER_CONSTANT, Scalar.all(0));

		List<Mat> planes = new ArrayList<Mat>();
		planes.add(padded);
		planes.add(Mat.zeros(padded.size(), padded.type()));
		Mat complexI = new Mat(padded.size(), padded.type());
		Core.merge(planes, complexI); // Add to the expanded another plane with zeros
		Mat complexITmp = new Mat(complexI.size(), complexI.type());
		complexI.convertTo(complexITmp, CvType.CV_32FC2);

		Core.dft(complexITmp, complexI); // this way the result may fit in the source matrix

		// compute the magnitude and switch to logarithmic scale
		// => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))
		planes = new ArrayList<Mat>();
		Core.split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
		Core.magnitude(planes.get(0), planes.get(1), planes.get(0));// planes[0] = magnitude
		Mat magI = planes.get(0);

		Mat magITmp = new Mat(magI.size(), magI.type());
		Core.add(magI, Scalar.all(1), magITmp);// switch to logarithmic scale
		Core.log(magITmp, magI);

		// crop the spectrum, if it has an odd number of rows or columns
		magI = new Mat(magI, new Rect(0, 0, magI.cols() & -2, magI.rows() & -2));

		// rearrange the quadrants of Fourier image so that the origin is at the image center
		int cx = magI.cols() / 2;
		int cy = magI.rows() / 2;

		Mat q0 = magI.submat(new Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant
		Mat q1 = magI.submat(new Rect(cx, 0, cx, cy)); // Top-Right
		Mat q2 = magI.submat(new Rect(0, cy, cx, cy)); // Bottom-Left
		Mat q3 = magI.submat(new Rect(cx, cy, cx, cy)); // Bottom-Right

		Mat tmp = new Mat(); // swap quadrants (Top-Left with Bottom-Right)
		q0.copyTo(tmp);
		q3.copyTo(q0);
		tmp.copyTo(q3);

		q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left)
		q2.copyTo(q1);
		tmp.copyTo(q2);

		magITmp = new Mat(magI.size(), magI.type());
		Core.normalize(magI, magITmp, 0, 255, Core.NORM_MINMAX); // Transform the matrix with float values into a
		// viewable image form (float between values 0 and 1).
		FileOutputStream fos = new FileOutputStream("data/dft.txt");
		fos.write(magITmp.dump().getBytes());
		fos.flush();
		fos.close();
		Highgui.imwrite(new File("data/dft.jpg").getAbsolutePath(), magITmp);// Show the result
	}

}
